# pragma once

# include <cstdint>
# include <math.h>
# include "MathCommon.h"

namespace glimmer{

    /// @brief 返回某数组的长度
    template<typename T, size_t SizeOfArray>
    constexpr size_t ElementCount(T(&)[SizeOfArray]){ return SizeOfArray; }

    template <typename T>
    struct Vec2Type
    {
        union
        {
            T data[2];               // array
            struct { T x, y; };      // x,y
            struct { T u, v; };      // u,v
        };
        
        Vec2Type<T>() {};
        Vec2Type<T>(const T& _v) : x(_v), y(_v){};
        Vec2Type<T>(const T& _x, const T& _y) : x(_x), y(_y) {};

        T& operator[](int rowIndex)
		{
			GLIMMER_ASSERT(rowIndex < 2);
			return data[rowIndex];
		}

		bool operator==(const Vec2Type<T>& vec) const
		{
			bool c1 = Equals(x, vec.x)
			auto c2 = Equals(y, vec.y)
			return c1 && c2;
		}

        bool operator!=(const Vec2Type<T>& vec) const{
            return !(*this == vec);
        }

		Vec2Type<T> operator+(const Vec2Type<T>& vec) const
		{
			Vec2Type<T> ret;
			ret.x = x + vec.x;
			ret.y = y + vec.y;
			return ret;
		}

		Vec2Type<T> operator-(const Vec2Type<T>& vec) const
		{
			Vec2Type<T> ret;
			ret.x = x - vec.x;
			ret.y = y - vec.y;
			return ret;
		}

		Vec2Type<T> operator*(T scale)  const
		{
			Vec2Type<T> ret;
			ret.x = x * scale;
			ret.y = y * scale;
			return ret;
		}
    
        /// @brief 向量模长的平方
        T SqrMagnitude() const {
            return x * x + y * y;
        }
    
        /// @brief 向量模长
        float Magnitude() const {
            return sqrt(SqrMagnitude());
        }
    
        /// @brief 向量的单位向量
        void Normalize()
		{
			float lengthScale = 1.0 / Magnitude();
			for (size_t i = 0; i < 2; ++i)
			{
				data[i] = data[i] * lengthScale;
			}
		}
    
        /// @brief 使用新向量构造一枚单位向量
        Vec2Type<float> NormalizeCopy() const
		{
			Vec2Type<float> ret;
			float lengthScale = 1.0 / Magnitude();
			for (size_t i = 0; i < 2; ++i)
			{
				ret.data[i] = data[i] * lengthScale;
			}
			return ret;
		}
   
        /// @brief 向量点乘
        T Dot(const Vec2Type<T>& vec) const
		{
			T result = 0;
			for (size_t i = 0; i < 2; ++i)
			{
				result += data[i] * vec.data[i];
			}
			return result;
		}
    };
    typedef Vec2Type<float> Vec2;

    template <typename T>
    struct Vec3Type
    {
        union 
        {
            T data[3];
            struct { T x, y, z; };
            struct { T r, g, b; };
        };
        
        Vec3Type<T>(){};
        Vec3Type<T>(const T& _v) : x(_v), y(_v), z(_v){};
        Vec3Type<T>(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z){};

        T& operator[](int rowIndex)
		{
			GLIMMER_ASSERT(rowIndex < 3);
			return data[rowIndex];
		}

		Vec3Type<T> operator+(const Vec3Type<T>& vec) const
		{
			Vec3Type<T> ret;
			ret.x = x + vec.x;
			ret.y = y + vec.y;
			ret.z = z + vec.z;
			return ret;
		}

		Vec3Type<T> operator-(const Vec3Type<T>& vec) const
		{
			Vec3Type<T> ret;
			ret.x = x - vec.x;
			ret.y = y - vec.y;
			ret.z = z - vec.z;
			return ret;
		}

		Vec3Type<T> operator*(T scale) const
		{
			Vec3Type<T> ret;
			ret.x = x * scale;
			ret.y = y * scale;
			ret.z = z * scale;
			return ret;
		}

		friend Vec3Type<T> operator*(T scale, const Vec3Type<T>& vec)	
		{
			Vec3Type<T> ret;
			ret.x = vec.x * scale;
			ret.y = vec.y * scale;
			ret.z = vec.z * scale;
			return ret;
		}

		bool operator==(const Vec3Type<T>& vec) const
		{
			auto c1 = Equals(x, vec.x);
			auto c2 = Equals(y, vec.y);
			auto c3 = Equals(z, vec.z);
			return c1 && c2 && c3;
		}

        bool operator!=(const Vec3Type<T>& vec) const{
            return !(*this == vec);
        }
    
        /// @brief 向量模长平方
        T SqrMagnitude() const{
            return x * x + y * y + z * z;
        }

        /// @brief 向量模长
        float Magnitude() const
		{
			return sqrt(SqrMagnitude());
		}

        /// @brief 向量叉乘
        Vec3Type<T> Cross(const Vec3Type<T>& lhs) const
		{
			Vec3Type<T> result;
			result[0] = data[1] * lhs.data[2] - data[2] * lhs.data[1];
			result[1] = data[2] * lhs.data[0] - data[0] * lhs.data[2];
			result[2] = data[0] * lhs.data[1] - data[1] * lhs.data[0];
			return result;
		}

		/// @brief 向量点乘
		T Dot(const Vec3Type<T>& lhs)	const
		{
			T result = 0;
			for (size_t i = 0; i < 3; ++i) 
			{
				result += data[i] * lhs.data[i];
			}
			return result;
		}

		/// @brief 单位向量
		void Normalize()
		{
			float lengthScale = 1.0f / Magnitude();
			for (size_t i = 0; i < 3; ++i)
			{
				data[i] = data[i] * lengthScale;
			}
		}

		/// @brief 使用新向量构造一枚单位向量
		Vec3Type<float> NormalizeCopy() const
		{
			V e c<float> ret;
			float lengthScale = 1.0f / Magnitude();
			for (size_t i = 0; i < 3; ++i)
			{
				ret.data[i] = data[i] * lengthScale;
			}
			return ret;
		}
    };
    typedef Vec3Type<float> Vec3;
    typedef Vec3Type<int> Vec3Int;

    template <typename T>
    struct Vec4Type
    {
        union 
        {
            T data[4];
            struct { T x, y, z, w; };
            struct { T r, g, b, a; };
        };
        
        Vec4Type<T>(){};
        Vec4Type<T>(const T& _v) : x(_v), y(_v), z(_v), w(_v){};
        Vec4Type<T>(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w){};
        Vec4Type<T>(const Vec3Type<T>& v3) : x(v3.x), y(v3.y), z(v3.z), w(1.0f) {};
		Vec4Type<T>(const Vec3Type<T>& v3, const T& _w) : x(v3.x), y(v3.y), z(v3.z), w(_w) {};

        T& operator[](int rowIndex)
		{
			GLIMMER_ASSERT(rowIndex < 4);
			return data[rowIndex];
		}

		Vec4Type<T> operator+(const Vec4Type<T>& rhs) const
		{
			Vec4Type<T> ret;
			ret.x = x + rhs.x;
			ret.y = y + rhs.y;
			ret.z = z + rhs.z;
			ret.w = w + rhs.w;
			return ret;
		}

		Vec4Type<T> operator-(const Vec4Type<T>& rhs) const
		{
			Vec4Type<T> ret;
			ret.x = x - rhs.x;
			ret.y = y - rhs.y;
			ret.z = z - rhs.z;
			ret.w = w - rhs.w;
			return ret;
		}

		Vec4Type<T> operator*(T scale) const
		{
			Vec4Type<T> ret;
			ret.x = x * scale;
			ret.y = y * scale;
			ret.z = z * scale;
			ret.w = w * scale;
			return ret;
		}

		friend Vec4Type<T> operator*(T scale, const Vec4Type<T>& lhs) 
		{
			Vec4Type<T> ret;
			ret.x = lhs.x * scale;
			ret.y = lhs.y * scale;
			ret.z = lhs.z * scale;
			ret.w = lhs.w * scale;
			return ret;
		}

		bool operator==(const Vec4Type<T>& rhs) const
		{
			auto c1 = Equals(x, rhs.x);
			auto c2 = Equals(y, rhs.y);
			auto c3 = Equals(z, rhs.z);
			auto c4 = Equals(w, rhs.w);
			return c1 && c2 && c3 && c4;
		}

        bool operator!=(const Vec4Type<T>& rhs) const
        {
            return !(*this == rhs);
        }

        T SqrMagnitude() const
		{
			return x * x + y * y + z * z + w * w;
		}

		float Magnitude() const
		{
			return sqrt(SqrMagnitude());
		}

		void Normalize()
		{
			float lengthScale = 1.0 / Magnitude();
			for (size_t i = 0; i < 4; ++i)
			{
				data[i] = data[i] * lengthScale;
			}
		}

		Vec4Type<float> NormalizeCopy() const
		{
			Vec4Type<float> ret;
			float lengthScale = 1.0 / Magnitude();
			for (size_t i = 0; i < 4; ++i)
			{
				ret.data[i] = data[i] * lengthScale;
			}
			return ret;
		}

		T Dot(const Vec4Type<T>& lhs) const
		{
			T result = 0;
			for (size_t i = 0; i < 4; ++i)
			{
				result += data[i] * lhs.data[i];
			}
			return result;
		}
    };

    typedef Vec4Type<float> Vec4;
    typedef Vec4Type<uint8_t> RGBA;
    typedef Vec4Type<int> Vec4Int;
    typedef Vec4Type<float> Color;
}